'''

http://en.wikipedia.org/wiki/List_of_medical_roots,_suffixes_and_prefixes

Created on May 7, 2011

@author: matt
'''

import sys
import urllib2
import re
import random

def starts_with_vowel(str_to_test):
    """
    Returns True if the first character of str_to_test is a vowel in English;
    False otherwise.
    """
    
    if str_to_test == None or str_to_test == '':
        return False
    
    vowels = ['aeiouyAEIOUY']
    
    if str_to_test[0] in vowels:
        return True
    else:
        return False

class AffixType(object):
    PREFIX = 0
    SUFFIX = 1
    
class Affix(object):
    """
    In linguistics, an affix is a morpheme (i.e., a word component) that can
    be attached to a word stem to make a new word. That is, prefixes and
    suffixes are affixes. (There are other kinds of affixes, too.)
    """
    
    def __init__(self, affix_body, affix_type):
        self.affix_body = affix_body
        self.connectors = []
        self.affix_type = affix_type
        
    def add_connector(self, connector):
        """
        Adds the specified connector (a string) to the list  of connectors
        """
        self.connectors.append(connector)
        
    def make_new_word(self, other_affix):
        """
        Concatenates other_affix with this object's affix to create a new word,
        which is returned as a string. Note that if this object represents a
        suffix, then other_affix should represent a prefix (and vice versa).
        """
        
        # If this is a prefix and the other is a suffix, concatenate this one
        # with the other one, with a connector inbetween (if applicable)
        if self.affix_type == AffixType.PREFIX and \
           other_affix.affix_type == AffixType.SUFFIX:
            
            # If the first character of the suffix is a vowel, or if we don't
            # have any connectors, then don't bother with the connector 
            # character
            
            if starts_with_vowel(other_affix.affix_body) or not self.connectors:
                new_word = self.affix_body + other_affix.affix_body
            else:
                # For now, just use the first connector we have
                new_word = self.affix_body + self.connectors[0] + other_affix.affix_body
     
        # If this is a suffix and other is a prefix, call this method again,
        # but with the arguments reversed       
        elif other_affix.affix_type == AffixType.PREFIX and \
           self.affix_type == AffixType.SUFFIX:

#            new_word = Affix.make_new_word(other_affix, self)
            new_word = other_affix.make_new_word(self)
        
        # If this is not a prefix/suffix combination, then raise an exception
        # that the caller can deal with. 
        else:
            # TODO: Verify that we shouldn't actually be raising some more
            # specific kind of exception
            raise Exception("Couldn't create a new word; must supply exactly "+
                            "one prefix and one suffix as arguments")

        return new_word
    
    def __unicode__(self):
        result = 'affix_body: ' + self.affix_body + ', affix_type: ' + str(self.affix_type)
        result += ', connectors: '
        result += ';'.join([conn for conn in self.connectors])
        return result
    
    def __str__(self):
        return self.__unicode__()
        
if __name__ == '__main__':
    print '-- Medical Prefix/Suffix Grabber --'
    
    source_url = 'http://en.wikipedia.org/wiki/List_of_medical_roots,_suffixes_and_prefixes'
    
    prefix_out_filename = sys.argv[1]
    suffix_out_filename = sys.argv[2]
    
    print 'Reading from URL %s' % (source_url)
    print 'Writing prefixes to %s' % (prefix_out_filename)
    print 'Writing suffixes to %s' % (suffix_out_filename)
    
    prefixes = []
    suffixes = []
    
#    http_headers = {'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11'}
    request = urllib2.Request(source_url)
    request.add_header('User-Agent', 'Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11')
    
    # Open the connection to the URL and read the content into a string
#    url_conn = urllib2.urlopen(source_url)
    url_conn = urllib2.urlopen(request)
    page_contents = url_conn.read()
    
    # Extract the section of the page we care about; the 'DOTALL' ensures that
    # the dot (in .*) includes newlines, which is not the case by default.
    prefix_section_match = re.search('id="Prefixes_and_suffixes.*id="English_meanings',
                                     page_contents, re.DOTALL)
    if prefix_section_match:
        prefix_section = prefix_section_match.group()
    else:
        raise Exception("Couldn't find the prefix/suffix section in the page")
     
    # Grab the text that's sandwiched between <td><b> and </b></td>' tags
#    payloads = re.findall('<td><b>(.*)</b></td>', page_contents)
    #English_meanings
    payloads = re.findall('<td><b>(.*)</b></td>', prefix_section)
    
    prefixes = []
    suffixes = []
    
    for payload in payloads:
        print 'Payload is %s' % (payload)
        
        # Split based on commas
        elements = payload.split(',')
        for element in elements:
            element = element.strip()  # Remove leading/trailing whitespace
            
            if element[-1] == '-':
                print '%s is a prefix' % (element)
                
                # Note that the '?' tells the .* to be non-greedy
                body_connector_match = re.search('(.*?)\((.*?)\)-', element)
                
                affix_body = None
                connector = None
                
                if body_connector_match:
                    affix_body = body_connector_match.group(1)
                    connector = body_connector_match.group(2)
                else:
                    # It seems no parens were present, so use the whole thing
                    body_match = re.search('(.*)-', element)
                    
                    if not body_match:
                        # TODO: Raise an exception here and catch it in the right loop
                        print "Warning: can't extract body/connector for %s" % (element)
                        
                    affix_body = body_match.group(1)
                      
                affix = Affix(affix_body, AffixType.PREFIX)
                if connector:
                    affix.add_connector(connector)
                
                print 'Constructed Affix:', affix
                prefixes.append(affix)
                
            elif element[0] == '-':
                print '%s is a suffix' % (element)
                # TODO: implement this
                # It seems no parens were present, so use the whole thing
                body_match = re.search('-(.*)', element)
                
                if not body_match:
                    # TODO: Raise an exception here and catch it in the right loop
                    print "Warning: can't extract body/connector for %s" % (element)
                    
                affix_body = body_match.group(1)
                affix = Affix(affix_body, AffixType.SUFFIX)
                if connector:
                    affix.add_connector(connector)

                print 'Constructed Affix:', affix
                suffixes.append(affix)
                
            else:
                print "Can't tell what %s is" % (element)
    
    # Generate some words
    for i in range(1000):
        prefix = random.choice(prefixes)
        print prefix.make_new_word(random.choice(suffixes))
    
    # If it has a trailing hypen, it's a prefix, so remove the hypen and store
    # it in the prefix list
    
    # If it has a leading hyphen, it's a suffix